package com.infinitegroup.findmystuff.models;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.infinitegroup.findmystuff.presenters.Constants;
import android.content.Context;
import android.location.Address;


/**
 * Establishes a link to the database (users table). Manages all connections and other back-end operations.
 * An instance of this class holds information about a user. Presenters are advised to access the database through this link. 
 * @author Rohit
 *
 */
public class AccountLink implements Account, Admin {
	
	private String id = "", firstName = "", lastName = "", username="", password="",
			email="", phone="", zipcode="", requestedItems = "";
	private boolean active=false, admin=false;
	private List<Map<String,String>> items;
	private DatabaseLink db;
	private Context context;

	/**
	 * Constructor for AccountLink
	 * @param username the user whose details are to be fetched. If parameter entered is an empty string all fields will be set to empty strings.
	 * @param context the android context from which this link was created.
	 */
	public AccountLink(String username, Context context){
		this.context = context;
		db = new DatabaseLink(context);
		db.open(); db.close(); // set the tables for the first activity.
		if (!username.equals("")){ // do not get details when creating a new account.
			fetchAccountDetails(username); // handles open/close.
			items = fetchAssociatedItems(username);
		}
	}

	
	/**
	 * Fetch the user's account details from the database. The method then populates this object's fields.
	 */
	private HashMap<String, String> fetchAccountDetails(String username){
		db.open();
		HashMap<String, String> map = db.getUser(username);
		db.close();
		if (map!=null){
			this.id = map.get(Constants.ACCOUNT_ID);
			this.firstName = map.get("firstname"); // change to keys.
			this.lastName = map.get("lastname");
			this.username = map.get("username");
			this.password = map.get("password");
			this.email = map.get("email");
			this.phone = map.get("phone");
			this.zipcode = map.get("zipcode");
			if (map.get("active").equals("1")){
				this.active=true;
			}
			if (map.get("admin").equals("1")){
				this.admin = true;
			}
			System.out.println(""+password+ "  "+ firstName + " " + lastName);
			return map;
		}
		return null;
	}
	
	/**
	 * Goes to the database and populates the item instance variable of this object (if username is valid).
	 */
	private List<Map<String,String>> fetchAssociatedItems(String username){
		db.open();
		List<Map<String, String>> list = db.getItems(username);
		db.close();
		items = list;
		return list;
	}
	
	
	@Override
	/**
	 * Deletes an item for this account.
	 */
	public long deleteItem(String itemId) {
		db.open();
		db.deleteEntry(db.DATABASE_TABLE_ITEMS, itemId);
		db.close();
		return 0;
	}

	@Override
	public void deactivate() {
		if (username!=""){
			active = false;
			db.open();
			db.updateEntry(db.DATABASE_TABLE_USERS, this.id, Constants.ACCOUNT_ACTIVE, String.valueOf(0));
			db.close();
		}
	}

	@Override
	public boolean isActive() {
		return active;
	}

	@Override
	public boolean isAdmin() {
		return admin;
	}

	@Override
	public boolean changePassword(String newPassword) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	/**
	 * Adds a user to the database. Trusts presenter.
	 * @return true if successfully registered, false otherwise.
	 */
	public boolean register(String firstName, String lastName, String username,
			String password, String email, String phone, String zipCode) {
		
		db.open();
		long id = db.insertUser(firstName, lastName, email, username, password, phone, zipCode, true, false);
		db.close();
		if (id != 0){
			return true; // Registration Successful.
		}
		return false; // Could not register.
	}
	
	@Override
	public void refresh(String username) {
		this.username = "";
		this.password = "";
		this.firstName = "";
		this.lastName = "";
		this.email = "";
		this.phone = "";
		this.zipcode = "";
		this.requestedItems = "";
		this.active = false;
		this.admin = false;
		
		fetchAccountDetails(username);
		if (this.username!="" ){
			fetchAssociatedItems(username);
		}
	}
	
	@Override
	public String getFirstName() {
		return this.firstName;
	}

	@Override
	public String getPassword() {
		
		return password;
	}

	@Override
	public String getEmail() {
		return email;
	}

	@Override
	public String getUsername() {
		return username;
	}

	@Override
	public String getPhone() {
		return phone;
	}

	@Override
	public String getZipcode() {
		return zipcode;
	}
	
	public String getId(){
		return id;
	}

	

	@Override
	/**
	 * Checks if an account already exists.
	 * @param username The username to check.
	 */
	public boolean exists(String username) {
		db.open();
		boolean result = db.entryExists(username, db.DATABASE_TABLE_USERS);
		db.close();
		return result;
	}

	@Override
	public String getLastName() {
		return lastName;
	}

	@Override
	public List<Map<String, String>> getAccountItems() {
		return items;
	}

	@Override
	public List<Map<String, String>> getLockedAccounts() {
		db.open();
		List<Map<String, String>> list = db.getSelectedUsers(Constants.ACCOUNT_ACTIVE, "0");
		db.close();
		return list;
	}

	
	@Override
	public void checkSuperAdmin(){
		if (!exists("superadmin")){
			System.out.println("registering super admin");
			db.open();
			db.insertUser("Chuck Norris", "password", "super@findmystuff.com", "superadmin", "password", "1234567890", "12345", true, true);
			db.close();
		}
	}

	/**
	 * Registers a new admin. Can be registered only by another admin.
	 */
	@Override
	public long registerNewAdmin(String firstName, String lastName,
			String email, String username, String password, String phone,
			String zipcode, boolean active) {
		long id = 0;
		db.open();
		id = db.insertUser(firstName, lastName, email, username, password, phone, zipcode, active, true);
		db.close();
		return id;
	}
	
	@Override
	public void unlockAccount(String username) {
		db.open();
		db.updateEntry(db.DATABASE_TABLE_USERS, username, Constants.ACCOUNT_ACTIVE, String.valueOf(1));
		db.close();
	}
	
	@Override
	public void deleteAccount(String username) {
		db.open();
		db.deleteEntry(db.DATABASE_TABLE_USERS, username);
		db.deleteEntry(db.DATABASE_TABLE_ITEMS, username);
		db.close();
	}
	

	@Override
	public String setPassword() {
		// TODO Auto-generated method stub
		return null;
	}


	@Override
	public String setEmail(String username, String newEmail) {
		// TODO Auto-generated method stub
		return null;
	}


	@Override
	public String setAddress(String username, String address) {
		// TODO Auto-generated method stub
		return null;
	}


	@Override
	public String setPhone(String username, String password) {
		// TODO Auto-generated method stub
		return null;
	}


	@Override
	public String setZipcode(String username, String zipcode) {
		// TODO Auto-generated method stub
		return null;
	}


	@Override
	public String request(String itemID){
		String result = null;
		if (!this.username.equals("")){ // don't do anything if the username is blank.
			requestedItems += itemID + ",";
			Item item = new ItemLink(context); // Unfortunately, we cannot avoid using contexts.
			Map<String, String> i = item.getItem(itemID); // item is simply a map.
			String requests = i.get(Constants.ITEM_REQUESTED_BY);
			if (requests == null){
				requests = username + ",";
			} else{
				requests += username + ",";
			}
			db.open();
			db.updateEntry(db.DATABASE_TABLE_ITEMS, itemID, Constants.ITEM_REQUESTED_BY, requests);
			db.updateEntry(db.DATABASE_TABLE_USERS, this.id, Constants.ACCOUNT_REQUESTED_ITEMS, requestedItems);
			db.close();
			result = requests;
		}
		return result;
	}	
}
